#include "server.h"

void  server::init()
{
#ifdef _WIN32
    WSADATA wsa;
    if(WSAStartup(0x0202,&wsa) == -1)
    {
        cout<<"Winsock Init failed!!"<<endl;
        exit(-1);
    }
    else
    {


#endif
        try
        {

            getparametter();
            user = new string[num_cl];
            num_map = rand()%3+6;//<6-8>
            table = new map(num_map);
            point = new  int[num_cl];
            for(unsigned int i = 0 ; i <num_cl ; i++)
            {
                point[i] = 0;
            }

        }
        catch(exception &e)
        {
            cout<<"Server Init failed : "<<e.what()<<endl;
            cin.get();
            exit(-1);
        }
#ifdef _WIN32
    }
#endif


}
//lay para can thiet
void server::getparametter()
{
    this->port = 9999;
    this->num_cl = 4;
    cout<<endl;
    while(num_cl > 3 || num_cl <=0 )
    {
        cout<<endl<<"Number client <1-3>:";
        cin>>this->num_cl;
    }

}
int server::createsocket()
{
    try
    {

        sv_lis = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
        if(sv_lis < 0 )
        {
            cout<<"Create socket failed "<<endl;
			#ifdef _WIN32
			WSACleanup();
			#endif
            return -1;

        }
        else
        {
            cout<<"Socket created ... "<<endl;
            cl_con = new int[num_cl];

            return 1;
        }
    }
    catch(exception &e)
    {
        cout<<"Create socket failed : "<<e.what()<<endl;
        cin.get();
        exit(-2);
    }


}
int server::serverlisten()
{
    try
    {
        if(serverbind() == 1)
        {

            if(listen(sv_lis,num_cl) <0)
            {
                cout<<"Server could not listen ... "<<endl;
				#ifdef _WIN32
				WSACleanup();
				#endif
                return -1;
            }
            else
            {
                cout<<"Server listenning ... "<<endl;
                return 1;
            }
        }
        else
        {
            return -1;
        }
    }
    catch(exception &e)
    {
        cout<<"Listen failed : "<<e.what()<<endl;
        cin.get();
        exit(-3);
    }
}
int server::serveraccept()
{
    for(unsigned int i=0; i<num_cl; i++)
    {
        try
        {
            //CSocket sock_client;
            int len = sizeof(client);
            cl_con[i] = accept(sv_lis,(sockaddr*)&client,&len);
            if(cl_con[i] < 0)
            {
                cout<<"Accept failed "<<endl;
				#ifdef _WIN32
				WSACleanup();
				#endif
                return -1;
            }
            else
            {
                cout<<"Acepted : "<<cl_con[i]<<endl;
            }
        }
        catch(exception &e)
        {
            cout<<"Accept failed : "<<e.what()<<endl;

        }

    }
    return 1;


}
int server::serverbind()
{
    serv.sin_family = AF_INET;
    serv.sin_port = htons(port);
    serv.sin_addr.s_addr = inet_addr("127.0.0.1");
    try
    {
        if(bind(sv_lis,(sockaddr*)&serv,sizeof(serv)) < 0 )
        {
            cout<<"Bind failed"<<endl;
            #ifdef _WIN32
			WSACleanup();
			#endif
            return -1;
        }
        else
        {
            cout<<"Bind successful"<<endl;
            return 1;
        }
    }
    catch(exception &e)
    {
        cout<<"Bind failed : "<<e.what()<<endl;
        cin.get();cin.get();
        exit(-4);
    }
}
int server::serversend(int id)
{

    try
    {

        int size = send(cl_con[id],(char *)&sen,sizeof(sen),0);
        return size;
    }
    catch(exception &e)
    {
        cout<<"Sent failed : "<<e.what()<<endl;
        return -1;
    }

}
int server::serversendall()
{
    for(unsigned int i = 0 ; i<num_cl ; i++)
    {
        if(serversend(i) <= 0)
		{
			return -1;
		}
    }
	return 1;
}
void server::serversrf()
{
			sen.setvalue(-10,-1,-1,"EXIT");
			serversendall();
			cout<<"Client disconected !!"<<endl;
			cout<<"Game could not continue "<<endl;
			cout<<"Close game ,server exit !!"<<endl;
			cin.get();cin.get();
			serverclose();
			exit(-1);
}
int server::serverrecv(int id)
{

    try
    {

        int size = recv(cl_con[id],(char*)&rec,sizeof(rec),0);
		return size;

    }
    catch(exception &e)
    {
        cout<<"Recvied failed : "<<e.what()<<endl;
    }


}
int server::login(int id)
{

    sen.setvalue(1,-1,-1,"USERGET");
    serversend(id);
    //cho nhan dc user name
    while(1)
    {
        serverrecv(id);
        if(checkuser(id) == 0)
        {
            serversend(id);
        }
        else
        {
            user[id] = rec.getmessage();
            cout<<"Accept user : "<<rec.getmessage()<<endl;
            break;
        }
    }

    sen.setvalue(2,-1,-1,"USEROK");
    serversend(id);

    return 1;
}
int server::checkuser(int id)
{

    string m="";
    string name ="";
    name+= rec.getmessage();
    transform(name.begin(),name.end(),name.begin(),::toupper);
	if(name.length() > 10 || name.length() < 3 )
    {
        return 0;
    }
	for(unsigned int i=0 ;i< name.length();i++)
	{
		if(checkchar(name[i]) == 0)
		{
			return 0;
		}
	}
    for(int i=0; i<id; i++)
    {
        m.assign(user[i]);
        transform(m.begin(),m.end(),m.begin(),::toupper);
        if(name.compare(m) == 0)
        {
            return 0;
        }
    }
    return 1;


}
int server::checkchar(char c)
{
	if(((c>=48)&&(c<=57)) || ((c>=65)&&(c<=90)) || ((c>=97)&&(c<=122)))
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
void server::makevaluegame()
{
    this->step = 8+6+1;
    srand(time(NULL));
    char **val = NULL;
	val = new char*[num_map];
	for(unsigned int i = 0;i<num_map;i++)
	{
		val[i] = new char[num_map];
	}
    for(unsigned int i = 0; i < num_map ; i++)
    {
        for(unsigned int j =0 ; j<num_map ; j++)
        {

            val[i][j] = '-';

        }
    }

    for(int t=0; t<2; t++)
    {


        int num=4;
        while(num > 2)
        {

again:
            unsigned int pos = rand()%num_map;
            unsigned int hor = rand()%2;//0 nam ngang,1 la thang


            if(pos >num_map - num)
            {

                if(hor == 0)
                {

                    for(int i=0; i<num; i++)
                    {
                        if(val[pos][pos-i] == 'X')
                        {
                            goto again;
                        }

                    }
                    for(int i=0; i<num; i++)
                    {

                        val[pos][pos-i] = 'X';

                    }
                    num--;
                }
                else
                {
                    for(int i=0; i<num; i++)
                    {
                        if(val[pos-i][pos] == 'X')
                        {
                            goto again;
                        }

                    }
                    for(int i=0; i<num; i++)
                    {

                        val[pos-i][pos] = 'X';

                    }
                    num--;
                }
            }
            else
            {
                if(hor == 0)
                {
                    for(int i=0; i<num; i++)
                    {
                        if(val[pos][pos+i] == 'X')
                        {
                            goto again;
                        }

                    }
                    for(int i=0; i<num; i++)
                    {
                        val[pos][pos+i] = 'X';

                    }
                    num--;
                }
                else
                {
                    for(int i=0; i<num; i++)
                    {
                        if(val[pos+i][pos] == 'X')
                        {
                            goto again;
                        }

                    }
                    for(int i=0; i<num; i++)
                    {
                        val[pos+i][pos] = 'X';

                    }
                    num--;

                }


            }
        }
    }
    while(1)
    {
        int one = rand()%num_map;
        if(val[one][one] == '-')
        {
            val[one][one] = 'X';
            break;
        }
    }

    for(unsigned int i = 0; i<num_map ; i++)
    {
        for(unsigned int j =0 ; j<num_map ; j++)
        {

            table->setvalue(val[i][j],i+1,j+1);

        }
    }



}
int server::processresult(int id)
{
    int x,y;
    x = rec.getx();
    y  = rec.gety();
    char c = table->getvalue(x,y);
    if(c == 'O')
    {
        //o da duoc chon roi
        return -1;
    }
    else if(c == 'X')
    {
            point[id] +=1;
            step--;
            table->setvalue('O',x,y);
            return 1;
    }
    else
    {
            table->setvalue('O',x,y);
            return 0;
    }

}
int  server::checkmax()
{
    int win = 0;
    win = point[0];
    for(unsigned int i=0;i<num_cl;i++)
    {
        if(point[i] > win)
        {
            win = point[i];
        }

    }
    return win;

}
void server::playgame()
{

    makevaluegame();
    unsigned int ste = 0;
    sen.setvalue(3,num_map,-1,"NUMMAP");
    if(serversendall() == -1)
	{
		serversrf();
	}
    while((step > 0) &&(ste <num_map*num_map))
    {
again:
        table->draw();
        sen.setvalue(4,-1,-1,"DOPLAY");
        int id;
        if(ste<num_cl)
        {
            id = ste;
        }
        else
        {
            id = ste%num_cl;
        }
        //yeu cau client nhap o can chon
        if(serversend(id) <= 0)
		{
			serversrf();
		}
        //cho nhan ket qua
        int get = serverrecv(id);
		if(get <= 0)
		{
			serversrf();
		}
        char c = table->getvalue(rec.getx(),rec.gety());
		int re = processresult(id); 
        if(re == -1)
        {
            sen.setvalue(-3,-1,-1,"BAD_CHOOSE");
            if(serversend(id) <= 0 )
			{
				serversrf();
			}
            goto again;
        }
        else if(re == 0)
        {
            //N la nothing
            string s="";
            s +='O';
            s += "\n";
            sen.setvalue(10,rec.getx(),rec.gety(),s);
            if( serversendall() == -1)
			{
				serversrf();
			}
        }
        else
        {
            //id = 10 la gui het cac client

            string d="";
            d += c;
            d +="\n";
            //can tahn cho nay,d la loa da chon dc
            sen.setvalue(10,rec.getx(),rec.gety(),d);
            if(serversendall() == -1)
			{
				serversrf();
			}

        }
        ste++ ;
    }
    //thong bao nguoi thang

    int result = checkmax();
    for(unsigned int i = 0;i<num_cl ;i++)
    {
        if(point[i] == result)
        {
            string con = "Congratulation to winner : " + user[i];
            sen.setvalue(8,-1,-1,con);
            serversendall();
        }

    }

    //9 thong bao diem
    for(unsigned int i=0; i<num_cl; i++)
    {
        sen.setvalue(9,point[i],-1,user[i]);
        serversendall();
    }
    sen.setvalue(0,-1,-1,"EXIT");
    serversendall();
    cin.get();
}
void server::control()
{
    init();
    if(createsocket() == 1)
    {



        while(1)
        {
            if(serverlisten() == 1)
            {

                if(serveraccept() == 1)
                {
                    for(unsigned int j =0 ; j<num_cl; j++)
                    {
                        login(j);

                    }
                    playgame();
                    table->draw();
                    cout<<"Game finished!!"<<endl;
                    cout<<"server exit"<<endl;
                    cin.get();
					break;
                }
			}
        }
		serverclose();
       // exit(0);
    }

}
void server::serverintro()
{
    cout<<"=========================== SOCKET PROGRAMMING =================================="<<endl;
    cout<<"\t\tProgramming with socket API"<<endl;
    cout<<"\t\t@Author :\tPham Van Diep"<<endl;
    cout<<"\t\t@Enviroment : c++ "<<endl;
    cout<<"\t\t@Port : 9999"<<endl<<endl;
}
void server::start()
{
    cout<<"\t************************************************************"<<endl;
    cout<<"\t\tRule of game:"<<endl;
    cout<<"\t\tServer start,you need to input number clients "<<endl;
    cout<<"\t\tNum of client <1-3>:"<<endl;
    cout<<"\t\tServer init and wait for client connect"<<endl;
    cout<<"\t\tClient havw to register a nickname,and game start."<<endl;
    cout<<"\t\tClient input num of row and col of map"<<endl;
    cout<<"\t\tServer process to calculate points"<<endl;
    cout<<"\t\tWhen all openned ,game will finished "<<endl;
    cout<<"\t\tServer will sent all points of clients"<<endl;
    cout<<"\t----------------------------------------------------------"<<endl;
    cout<<"\t\tStart game,please press 1 number"<<endl;
    cout<<"\t\tExit ,Press any key  "<<endl<<endl;
    cout<<"\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"<<endl;
    cout<<"You choose : ";
    int choose;
    cin>>choose;
    switch(choose)
    {
    case 1:
        control();
        break;
    default:
        exit(0);
        break;
    }
}
void server::serverclose()
{
#ifdef _WIN32
    for(unsigned int i=0; i<num_cl; i++)
    {
        closesocket(cl_con[i]);

    }
	closesocket(sv_lis);
    WSACleanup();
#endif
#ifdef linux
    for(unsigned int i=0; i<num_cl; i++)
    {
        close(cl_con[i]);

    }
	close(sv_lis);
#endif
    delete cl_con;
    delete table;
    delete point;
}
server::server()
{
    this->sv_lis = -1;
	this->num_cl = 0;
	this->cl_con = 0;
	this->num_map = 0;
	this->point = NULL;
	this->port = 0;
	this->user = NULL;
	this->table = NULL;
	this->point = NULL;
	this->step = 0;
}
server::~server()
{
    return;
}
void server::run()
{
    serverintro();
    start();
}


